package com.testapp.bluetoothtest08.cipher.impl;


import com.testapp.bluetoothtest08.cipher.UserCipherService;
import com.testapp.bluetoothtest08.cipher.entity.DataIndex;
import com.testapp.bluetoothtest08.cipher.entity.JoinCheck;
import com.testapp.bluetoothtest08.cipher.entity.JoinCheckStr;
import com.testapp.bluetoothtest08.cipher.entity.ScanCodeFirstRequest;
import com.testapp.bluetoothtest08.cipher.entity.ScanCodeSecondRequest;
import com.testapp.bluetoothtest08.cipher.entity.UserJoin;
import com.testapp.bluetoothtest08.cipher.entity.UserUpdate;
import com.testapp.bluetoothtest08.cipher.entity.user.UserPrivateData;
import com.testapp.bluetoothtest08.cipher.entity.user.UserPrivateDataStr;
import com.testapp.bluetoothtest08.cipher.entity.user.UserScanCodeData;
import com.testapp.bluetoothtest08.cipher.tool.MD5;
import com.testapp.bluetoothtest08.cipher.tool.NumberTools;
import com.testapp.bluetoothtest08.cipher.tool.Parameter;
import com.testapp.bluetoothtest08.cipher.tool.user.UserUniversalTools;
import com.testapp.bluetoothtest08.common.CustomException;

import lombok.AllArgsConstructor;


import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;


@AllArgsConstructor
public class UserCipherServiceImpl implements UserCipherService {

    private final UserUniversalTools userTools = new UserUniversalTools();
    private final NumberTools numberTools=new NumberTools();
    private final Parameter parameter = new Parameter();
    private final MD5 md5 = new MD5();

    @Override
    public List<Object> UserJoinRequest(String Cku, String Pku) {
        return this.UserJoinRequest(Cku, Pku, 100);
    }

    @Override
    public List<Object> UserJoinRequest(String Cku, String Pku, int length) {
        BigInteger CkuB, PkuB;
        if (Cku == null || Cku.equals("")) {
            CkuB = numberTools.generateNum(length);
            PkuB = parameter.B.modPow(CkuB, parameter.Sigma);
            Cku = CkuB.toString();
            Pku = PkuB.toString();
        } else {
            CkuB = new BigInteger(Cku);
            PkuB = new BigInteger(Pku);
        }

        UserJoin userJoin = new UserJoin();
        UserPrivateData userData = new UserPrivateData();
        userData.secList = userTools.getSecParams(CkuB);                                                     //set secret params

        BigInteger s;
        List<BigInteger> r = new ArrayList<>(9);
        BigInteger p1;
        BigInteger p2;
        BigInteger p3;
        BigInteger y1;
        BigInteger y2;
        BigInteger y3;
        r.add(numberTools.generateNum(DataIndex.INDEX_R0));                            //r0   random u
        BigInteger r1 = numberTools.generateNum(parameter.EpisilonLamK);                   //r1 random t1
        r.add(r1);
        r.add(numberTools.generateNum(parameter.EpisilonLamK));                            //r2 random x
        r.add(numberTools.generateNum(parameter.EpisilonLsigmaK));                            //r3 random s
        r.add(r1);                                                             //r4 random t1
        r.add(numberTools.generateNum(parameter.EpisilonLK));                            //r5 random i
        r.add(numberTools.generateNum(parameter.EpisilonLK));                            //r6 random e
        r.add(numberTools.generateNum(parameter.EpisilonLK));                            //r7 random d
        r.add(numberTools.generateNum(parameter.EpisilonLamK));                            //r8 random w


        BigInteger numc;
        String c = "";
        MD5 md5 = new MD5();
        p1 = parameter.B.modPow(r.get(0), parameter.Sigma);                //b^r0 mod sigma   random exp PKu
        p2 = parameter.B.modPow(r.get(1), parameter.Sigma);                //b^r1 mod sigma   random exp J1
        p3 = parameter.Qrn.Ax.modPow(r.get(2), parameter.N);
        p3 = p3.multiply(parameter.Qrn.As.modPow(r.get(3), parameter.N)).mod(parameter.N);
        p3 = p3.multiply(parameter.Qrn.At.modPow(r.get(4), parameter.N)).mod(parameter.N);
        p3 = p3.multiply(parameter.Qrn.Ai.modPow(r.get(5), parameter.N)).mod(parameter.N);
        p3 = p3.multiply(parameter.Qrn.Ae.modPow(r.get(6), parameter.N)).mod(parameter.N);
        p3 = p3.multiply(parameter.Qrn.Ad.modPow(r.get(7), parameter.N)).mod(parameter.N);
        p3 = p3.multiply(parameter.Qrn.h.modPow(r.get(8), parameter.N)).mod(parameter.N);
        BigInteger p4 = p3.multiply(parameter.Qrn.A).mod(parameter.N);                //    random exp J2
        c += parameter.B.toString() + parameter.Qrn.A.toString() + parameter.Qrn.Ax.toString() + parameter.Qrn.As.toString() + parameter.Qrn.At.toString() +
                parameter.Qrn.Ai.toString() + parameter.Qrn.Ae.toString() + parameter.Qrn.Ad.toString() + parameter.Qrn.h.toString();


        y1 = PkuB;                                                  // PKu
        y2 = parameter.B.modPow(userData.secList.get(1), parameter.Sigma);        //J1
        y3 = parameter.Qrn.Ax.modPow(userData.secList.get(2), parameter.N);
        y3 = y3.multiply(parameter.Qrn.As.modPow(userData.secList.get(3), parameter.N)).mod(parameter.N);
        y3 = y3.multiply(parameter.Qrn.At.modPow(userData.secList.get(4), parameter.N)).mod(parameter.N);
        y3 = y3.multiply(parameter.Qrn.Ai.modPow(userData.secList.get(5), parameter.N)).mod(parameter.N);
        y3 = y3.multiply(parameter.Qrn.Ae.modPow(userData.secList.get(6), parameter.N)).mod(parameter.N);
        y3 = y3.multiply(parameter.Qrn.Ad.modPow(userData.secList.get(7), parameter.N)).mod(parameter.N);
        y3 = y3.multiply(parameter.Qrn.h.modPow(userData.secList.get(8), parameter.N)).mod(parameter.N); //   J2/a
        c += y1.toString() + y2.toString() + y3.toString();
        c += p1.toString() + p2.toString() + p4.toString();
        c = md5.start(c);
        c = new BigInteger(c, 16).toString(2).substring(0, parameter.k - 1);
        c = new BigInteger(c, 2).toString(2);
        numc = new BigInteger(c, 2);

        userJoin.c = numc.toString();
        userJoin.y.add(y1.toString());
        userJoin.y.add(y2.toString());
        userJoin.y.add(y3.toString());
        userJoin.PKu = Pku;
        for (int i = 0; i < 9; i++) {
            s = r.get(i).subtract(numc.multiply(userData.secList.get(i)));
            userJoin.s.add(s.toString());
        }

        userData.c = CkuB;
        userData.p = PkuB;

        List<Object> list = new LinkedList<>();
        list.add(userJoin);
        list.add(userData);
        return list;
    }

    @Override
    public UserPrivateDataStr UserJoinResponse(UserPrivateData userData, JoinCheckStr joinCheckStr) {
        JoinCheck joinCheck = new JoinCheck(joinCheckStr);
        //verify A,y,t2
        if (joinCheck.t2.bitLength() != Parameter.Lamtha) {
            throw new CustomException(400, "t2 length error");
        }
        if (joinCheck.y.compareTo(parameter.Range4left) != 1 || joinCheck.y.compareTo(parameter.Range4right) != -1) {
            throw new CustomException(400, "y length error");
        }

        BigInteger p = parameter.Qrn.Ax.modPow(userData.secList.get(2), parameter.N);
        p = p.multiply(parameter.Qrn.As.modPow(userData.secList.get(3), parameter.N)).mod(parameter.N);
        p = p.multiply(parameter.Qrn.At.modPow(userData.secList.get(4), parameter.N)).mod(parameter.N);
        p = p.multiply(parameter.Qrn.Ai.modPow(userData.secList.get(5), parameter.N)).mod(parameter.N);
        p = p.multiply(parameter.Qrn.Ae.modPow(userData.secList.get(6), parameter.N)).mod(parameter.N);
        p = p.multiply(parameter.Qrn.Ad.modPow(userData.secList.get(7), parameter.N)).mod(parameter.N);
        p = p.multiply(parameter.Qrn.h.modPow(userData.secList.get(8), parameter.N)).mod(parameter.N);
        p = p.multiply(parameter.Qrn.A).mod(parameter.N);
        p = p.multiply(parameter.Qrn.At.modPow(joinCheck.t2, parameter.N)).mod(parameter.N);
        BigInteger Aa = joinCheck.a.modPow(joinCheck.y, parameter.N);                                                                      //A^y
        if (!Aa.equals(p)) {
            throw new CustomException(400, "a length error");
        }
        userData.a = joinCheck.a;
        userData.y = joinCheck.y;
        userData.t2 = joinCheck.t2;
        userData.secList.set(4, joinCheck.t2.add(userData.secList.get(4)));
        return new UserPrivateDataStr(userData);
    }

    //checked
    //list Object [UserScanCodeData userData, ScanCodeFirstRequest requestData]
    @Override
    public List<Object> scanCodeRequestFirst(UserPrivateData user) {
        UserScanCodeData userData = new UserScanCodeData();
        userData.rList = userTools.listR();

        userData.w2 = numberTools.generateNum(Parameter.Lamtha);                                                                                                    //w*
        userData.rand = numberTools.generateNum(Parameter.Lamtha);
        userData.rand_ = numberTools.generateNum(DataIndex.INDEX_T2);                                                                                              //r
        userData.A_ = user.a.multiply(parameter.Qrn.h.modPow(userData.w2, parameter.N)).mod(parameter.N);                                                            //A'=A*(h^w*) mod n
        userData.T = parameter.B1.modPow(user.secList.get(4), parameter.Sigma).multiply(parameter.B2.modPow(userData.rand, parameter.Sigma)).mod(parameter.Sigma);    //T = b1^t*b2^t mod sigma
        userData.e = user.secList.get(6);
        if(userData.e.mod(parameter.K_at).equals(BigInteger.ZERO)){
            userData.e = userData.e.add(BigInteger.ONE).mod(parameter.K_at);
            userData.flag2 = true;
        }
        userData.ec = user.secList.get(6).add(user.secList.get(7)).mod(parameter.K_at);                                                                             //ec = e+d mod K_at
        BigInteger e_inv = userData.e.modInverse(parameter.K_at);                                                                                                   //e^(-1)
        userData.m = userData.e.multiply(e_inv).divide(parameter.K_at);                                                                                             //(e*e^(-1)/K)
        userData.ic = user.secList.get(5).add(userData.e.modInverse(parameter.K_at)).mod(parameter.K_at);                                                           //ic = i+(e)^(-1)
        if (userData.ic.mod(Parameter.bigTwo).equals(Parameter.bigZero)) {                                                                                      //confirm that ic is odd
            userData.ic = userData.ic.add(Parameter.bigOne).mod(parameter.K_at);
            userData.flag = 1;
        }
        if (userData.ic.mod(Parameter.bigTwo).equals(Parameter.bigZero)) {                                                                                      //confirm that ic is odd
            userData.ic = userData.ic.add(Parameter.bigOne).mod(parameter.K_at);
            userData.flag = 2;
        }
        userData.ics = userData.ic.add(user.secList.get(3));                                                                                                        //ics = ic + s
        userData.ics_ = userData.ics.modInverse(parameter.OrderSignma);                                                                                             //ics_  = (ic+s)^(-1) mod ordersigma
        userData.ict = userData.ic.add(user.secList.get(4));//ict = ic + t
        userData.ict_ = userData.ict.modInverse(parameter.OrderSignma);                                                                                             //ict_  = (ic+t)^(-1) mod ordersigma
        userData.SN = parameter.B1.modPow(userData.ics_, parameter.Sigma).multiply(parameter.B2.modPow(userData.ict_, parameter.Sigma)).mod(parameter.Sigma);                        //SN = b1^(ics_)*b2^(ict_) (mod sigma)
        userData.w_ = user.secList.get(8).add(user.y.multiply(userData.w2)).mod(parameter.OrderN);                                                                  //w' = w + yw*
        //seclist 0-8
        try {                                                                                                                                                        //D = a*ax^(x)*as^(s)*at^(t)*ai^(i)*ae^(e)*ad^(d)*h^(w') mod n
            ArrayList<BigInteger> dExponentList = new ArrayList<>();
            dExponentList.add(BigInteger.ONE);
            dExponentList.add(user.secList.get(2));
            dExponentList.add(user.secList.get(3));
            dExponentList.add(user.secList.get(4));
            dExponentList.add(userData.ic);
            dExponentList.add(userData.ec);
            dExponentList.add(user.secList.get(7));
            dExponentList.add(userData.w_);
            userData.D = numberTools.modPowList(parameter.Qrn.QRList.toArray(new BigInteger[parameter.Qrn.QRList.size()]), dExponentList.toArray(new BigInteger[dExponentList.size()]), parameter.N);
        } catch (Exception e) {
            System.out.println(e);
            throw new CustomException(400, "secList content error");
        }                                                                                                        //r'
        userData.T1 = parameter.B1.modPow(user.secList.get(5), parameter.Sigma).multiply(parameter.B2.modPow(userData.rand_, parameter.Sigma)).mod(parameter.Sigma);   //T1 = b1^(i)*b2^(r') mod sigma
        userData.T2 = userData.T1.modPow(user.secList.get(6), parameter.Sigma);                                                                                       //T2 = T1^e mod sigma
        userData.dA_ = numberTools.modPowList(parameter.Qrn.QRPList.toArray(new BigInteger[parameter.Qrn.QRPList.size()]), userData.rList.subList(1, 8).toArray(new BigInteger[7]), parameter.N);    //dA_ = ax^(r2)*as^(r3)*at^(r4)*ai^(r5)*ae^(r6)*ad^(r7)*h^(r8) mod n
        userData.dA_ = userData.dA_.modInverse(parameter.N);
        userData.dA = userData.A_.modPow(userData.rList.get(0), parameter.N).multiply(userData.dA_).mod(parameter.N);                                                    //dA = (A')^(r1)/dA_ mod n
        userData.dT = parameter.B1.modPow(userData.rList.get(3), parameter.Sigma).multiply(parameter.B2.modPow(userData.rList.get(8), parameter.Sigma)).mod(parameter.Sigma); // dT = b1^(r4)*b2^(r9) mod sigma
        userData.dT1 = parameter.B1.modPow(userData.rList.get(4), parameter.Sigma).multiply(parameter.B2.modPow(userData.rList.get(9), parameter.Sigma)).mod(parameter.Sigma);// dT1 = b1^(r5)*b2^(r10) mod sigma
        userData.dT2 = userData.T1.modPow(userData.rList.get(5), parameter.Sigma);                                                                                    // dT2 = T1^(r6) mod sigma
        userData.dT2_ = parameter.B1.modPow(userData.rList.get(10), parameter.Sigma).multiply(parameter.B2.modPow(userData.rList.get(11), parameter.Sigma)).mod(parameter.Sigma); //dT2' = b1^(r11)*b2^(r12) mod sigma
        userData.dT3_ = userData.rList.get(12).subtract(userData.rList.get(5).add(userData.rList.get(6))).mod(parameter.K_at);                                       //dT3_ = r13-r6-r7
        userData.dT3 = parameter.B.modPow(userData.dT3_, parameter.Sigma);                                                                                            //dT3 = b^(dT3_) mod sigma
        if (userData.flag == 0) {
            userData.dic_ = userData.ic.multiply(userData.rList.get(5)).subtract(userData.rList.get(10)).mod(parameter.K_at);
            //dic_ = ic*r6 - r11-K_at * r14
        } else if (userData.flag == 1){
            userData.dic_ = userData.ic.subtract(Parameter.bigOne).multiply(userData.rList.get(5)).subtract(userData.rList.get(10)).mod(parameter.K_at);
        } else {
            userData.dic_ = userData.ic.subtract(Parameter.bigTwo).multiply(userData.rList.get(5)).subtract(userData.rList.get(10)).mod(parameter.K_at);
        }
        userData.dic = parameter.Qrn.A.modPow(userData.dic_, parameter.N);                                                                                            //dic = a^(dic_) mod n
        userData.dSN1 = userData.SN.modPow(userData.rList.get(2), parameter.Sigma).multiply(parameter.B2.modPow(userData.rList.get(14), parameter.Sigma).modInverse(parameter.Sigma)).mod(parameter.Sigma); //dSN1 = SN^(r3)*((b2)^(r15))^(-1) mod sigma
        userData.dSN2 = userData.SN.modPow(userData.rList.get(3), parameter.Sigma).multiply(parameter.B1.modPow(userData.rList.get(15), parameter.Sigma).modInverse(parameter.Sigma)).mod(parameter.Sigma); //dSN2 = SN^(r4)*((b1)^(r16))^(-1) mod sigma
        userData.dD = parameter.Qrn.Ax.modPow(userData.rList.get(1), parameter.N);                                                                                                   //dD = ax^(r2)*as^(r3)*at^(r4)*ae^(r13)*ad^(r7)*h^(r8) mod n
        userData.dD = userData.dD.multiply(parameter.Qrn.As.modPow(userData.rList.get(2), parameter.N)).mod(parameter.N);
        userData.dD = userData.dD.multiply(parameter.Qrn.At.modPow(userData.rList.get(3), parameter.N)).mod(parameter.N);
        userData.dD = userData.dD.multiply(parameter.Qrn.Ae.modPow(userData.rList.get(12), parameter.N)).mod(parameter.N);
        userData.dD = userData.dD.multiply(parameter.Qrn.Ad.modPow(userData.rList.get(6), parameter.N)).mod(parameter.N);
        userData.dD = userData.dD.multiply(parameter.Qrn.h.modPow(userData.rList.get(7), parameter.N)).mod(parameter.N);
        ScanCodeFirstRequest scanCodeFirstRequest = new ScanCodeFirstRequest(userData);
        userData.rand2 = userData.rList;

        //save userData
        List<Object> list = new ArrayList<>();
        list.add(userData);
        list.add(scanCodeFirstRequest);
        return list;
    }

    //checked
    @Override
    public ScanCodeSecondRequest scanCodeRequestSecond(UserPrivateData user, UserScanCodeData userData, ScanCodeFirstRequest requestData, String challenge) {
        ScanCodeSecondRequest checkData = new ScanCodeSecondRequest();

        String c = "";
        c += challenge + requestData.A_ + requestData.T + requestData.ic + requestData.SN + requestData.D + requestData.T1 +
                requestData.T2;
        for (int i = 0; i < requestData.d.size(); i++) {
            c += requestData.d.get(i);
        }
        c = md5.start(c);
        c = new BigInteger(c, 16).toString(2).substring(0, parameter.k - 1);
        c = new BigInteger(c, 2).toString(2);
        BigInteger numc = new BigInteger(c, 2);
        BigInteger s;                                                                                                   //generate s
        s = userData.rand2.get(0).subtract(numc.multiply(user.y.subtract(new BigInteger("2").pow(210))));             //s1 = r1-c(y-2^gama)
        checkData.s.add(s.toString());                                                                                      //
        s = userData.rand2.get(1).subtract(numc.multiply(user.secList.get(2)));                             //s2 = r2 - c*x
        checkData.s.add(s.toString());                                                                                      //
        s = userData.rand2.get(2).subtract(numc.multiply(user.secList.get(3)));                             //s3 = r3 - c*s
        checkData.s.add(s.toString());
        s = userData.rand2.get(3).subtract(numc.multiply(user.secList.get(4)));                             //s4 = r4 - c*t
        checkData.s.add(s.toString());
        s = userData.rand2.get(4).subtract(numc.multiply(user.secList.get(5)));                             //s5 = r5 - c*i
        checkData.s.add(s.toString());
        s = userData.rand2.get(5).subtract(numc.multiply(user.secList.get(6)));                             //s6 = r6 - c*e
        checkData.s.add(s.toString());
        s = userData.rand2.get(6).subtract(numc.multiply(user.secList.get(7)));                             //s7 = r7 - c*d
        checkData.s.add(s.toString());
        s = userData.rand2.get(7).subtract(numc.multiply(userData.w_));                                                       //s8 = r8 - c*w'
        checkData.s.add(s.toString());
        s = userData.rand2.get(8).subtract(numc.multiply(userData.rand));                                                     //s9 = r9 - c*r
        checkData.s.add(s.toString());
        s = userData.rand2.get(9).subtract(numc.multiply(userData.rand_));                                                    //s10 = r10 - c*r'
        checkData.s.add(s.toString());
        s = userData.rand2.get(10).subtract(numc.multiply(user.secList.get(5).multiply(user.secList.get(6)))); //s11 = r11 - c*i*e
        checkData.s.add(s.toString());
        s = userData.rand2.get(11).subtract(numc.multiply(userData.rand_.multiply(user.secList.get(6))));                        //s12 = r12 - c*r'*e
        checkData.s.add(s.toString());
        s = userData.rand2.get(12).subtract(numc.multiply(userData.ec));                                                                  //s13 = r13 - c*ec
        checkData.s.add(s.toString());
        s = userData.rand2.get(13).subtract(numc.multiply(userData.m));                                                                   //s14 = r14 - c*m
        checkData.s.add(s.toString());
        s = userData.rand2.get(14).subtract(numc.multiply(userData.ict_.multiply(userData.ics)));                                                  //s15 = r15 - c*(ic+t)^(-1)*(ic+s)
        checkData.s.add(s.toString());
        s = userData.rand2.get(15).subtract(numc.multiply(userData.ics_.multiply(userData.ict)));                                                  //s16 = r16 - c*(ic+s)^(-1)*(ic+t)
        checkData.s.add(s.toString());
        BigInteger R1 = userData.ics_.subtract(numc.multiply(user.secList.get(4)));                                                            //R1 = (ic+s)^(-1)-c*t
        checkData.R1 = R1.toString();
        BigInteger R2 = userData.ict_.subtract(numc.multiply(userData.rand));                                                                                    //R2 = (ic+t)^(-1)-c*r
        checkData.R2 = R2.toString();
        checkData.c = numc.toString();
        checkData.s6 = userData.rand2.get(5).subtract(numc.multiply(userData.e)).toString();
        checkData.s11 = userData.rand2.get(10).subtract(numc.multiply(user.secList.get(5).multiply(userData.e))).toString();
        return checkData;
    }

    //list Object [UserScanCodeData userData, ScanCodeFirstRequest requestFirst, ScanCodeSecondRequest requestSecond]
    @Override
    public List<Object> scanCodeRequestCombine(UserPrivateData user, String challenge) {
        List<Object> objects = scanCodeRequestFirst(user);
        UserScanCodeData userData = (UserScanCodeData) objects.get(0);
        ScanCodeFirstRequest requestFirst = (ScanCodeFirstRequest) objects.get(1);
        ScanCodeSecondRequest requestSecond = scanCodeRequestSecond(user, userData, requestFirst, challenge);
        List<Object> objectList = new LinkedList<>();
        objectList.add(userData);
        objectList.add(requestFirst);
        objectList.add(requestSecond);
        return objectList;
    }

    @Override
    public boolean changePrivateData(UserPrivateData user, UserScanCodeData userData, UserUpdate userUpdate) {
        user.secList.set(5,userData.ic);
        user.secList.set(6,userData.ec);
        user.secList.set(8,userData.w_);
        user.a = userUpdate.AD;
        user.y = userUpdate.y_;
        return true;
    }

    @Override
    public List<Object> scanCodeRequestFirstTest(UserPrivateData user) {
        UserScanCodeData userData = new UserScanCodeData();
        userData.rList = new ArrayList<>();
        userData.rList.add(new BigInteger("2454048499088907426850044654677680868840118763904718281454988"));
        userData.rList.add(new BigInteger("1729154999622464318104779462692092309174662337078239796248799"));
        userData.rList.add(new BigInteger("194046851434203066183852267735062205794413293657957485447006575063819119440798166309621241505820170849123044589947853815"));
        userData.rList.add(new BigInteger("2648108433319113667513394113894484281330918111266439707926740"));
        userData.rList.add(new BigInteger("2363732846917050118978855592389530"));
        userData.rList.add(new BigInteger("1993701000890375276106935966151994"));
        userData.rList.add(new BigInteger("1875257329371500252249677709280103"));
        userData.rList.add(new BigInteger("178787059232847684595937038117355439085935837868477200676109954216661703175284133717622466319746638644871232160298585277164911234784426266709677792683087834"));
        userData.rList.add(new BigInteger("1925990756054739847639759381591013923278652169461221006232408"));
        userData.rList.add(new BigInteger("2184895329618754109795547759470547243768678463285601758041259"));
        userData.rList.add(new BigInteger("47817344072691413283676940914868089932"));
        userData.rList.add(new BigInteger("56655430415432750701544498208470742478456414408132536535105729083"));
        userData.rList.add(new BigInteger("1530004010310155064457331794777250"));
        userData.rList.add(new BigInteger("1893223051216794616051781440019157"));
        userData.rList.add(new BigInteger("2007801680400108195757584475555843364022796629802812723610970649337539596215243987742470028794244404784213386264489182059543104887699802546391501514898760490971026743968920380275739384278658310713940742815682080"));
        userData.rList.add(new BigInteger("2586338660834897691960699471524765375965177001970781313063057323415630239936869180661291750738603799231803577020677978135307742488803756295512482987963794509270526230480672196462646732925737162065815758839022178"));

        userData.w2 = new BigInteger("847396559708088136536");                                                                                                    //w*
        userData.rand = new BigInteger("1173124413681130002761");
        userData.rand_ = new BigInteger("957403239301540735485");                                                                                              //r
        userData.A_ = user.a.multiply(parameter.Qrn.h.modPow(userData.w2, parameter.N)).mod(parameter.N);                                                            //A'=A*(h^w*) mod n
        userData.T = parameter.B1.modPow(user.secList.get(4), parameter.Sigma).multiply(parameter.B2.modPow(userData.rand, parameter.Sigma)).mod(parameter.Sigma);    //T = b1^t*b2^t mod sigma
        userData.e = user.secList.get(6);
        if(userData.e.mod(parameter.K_at).equals(BigInteger.ZERO)){
            userData.e = userData.e.add(BigInteger.ONE).mod(parameter.K_at);
            userData.flag2 = true;
        }
        userData.ec = user.secList.get(6).add(user.secList.get(7)).mod(parameter.K_at);                                                                             //ec = e+d mod K_at
        BigInteger e_inv = userData.e.modInverse(parameter.K_at);                                                                                                   //e^(-1)
        userData.m = userData.e.multiply(e_inv).divide(parameter.K_at);                                                                                             //(e*e^(-1)/K)
        userData.ic = user.secList.get(5).add(userData.e.modInverse(parameter.K_at)).mod(parameter.K_at);                                                           //ic = i+(e)^(-1)
        if (userData.ic.mod(Parameter.bigTwo).equals(Parameter.bigZero)) {                                                                                      //confirm that ic is odd
            userData.ic = userData.ic.add(Parameter.bigOne).mod(parameter.K_at);
            userData.flag = 1;
        }
        if (userData.ic.mod(Parameter.bigTwo).equals(Parameter.bigZero)) {                                                                                      //confirm that ic is odd
            userData.ic = userData.ic.add(Parameter.bigOne).mod(parameter.K_at);
            userData.flag = 2;
        }
        userData.ics = userData.ic.add(user.secList.get(3));                                                                                                        //ics = ic + s
        userData.ics_ = userData.ics.modInverse(parameter.OrderSignma);                                                                                             //ics_  = (ic+s)^(-1) mod ordersigma
        userData.ict = userData.ic.add(user.secList.get(4));//ict = ic + t
        userData.ict_ = userData.ict.modInverse(parameter.OrderSignma);                                                                                             //ict_  = (ic+t)^(-1) mod ordersigma
        userData.SN = parameter.B1.modPow(userData.ics_, parameter.Sigma).multiply(parameter.B2.modPow(userData.ict_, parameter.Sigma)).mod(parameter.Sigma);                        //SN = b1^(ics_)*b2^(ict_) (mod sigma)
        userData.w_ = user.secList.get(8).add(user.y.multiply(userData.w2)).mod(parameter.OrderN);                                                                  //w' = w + yw*
        //seclist 0-8
        try {                                                                                                                                                        //D = a*ax^(x)*as^(s)*at^(t)*ai^(i)*ae^(e)*ad^(d)*h^(w') mod n
            ArrayList<BigInteger> dExponentList = new ArrayList<>();
            dExponentList.add(BigInteger.ONE);
            dExponentList.add(user.secList.get(2));
            dExponentList.add(user.secList.get(3));
            dExponentList.add(user.secList.get(4));
            dExponentList.add(userData.ic);
            dExponentList.add(userData.ec);
            dExponentList.add(user.secList.get(7));
            dExponentList.add(userData.w_);
            userData.D = numberTools.modPowList(parameter.Qrn.QRList.toArray(new BigInteger[parameter.Qrn.QRList.size()]), dExponentList.toArray(new BigInteger[dExponentList.size()]), parameter.N);
        } catch (Exception e) {
            System.out.println(e);
            throw new CustomException(400, "secList content error");
        }                                                                                                        //r'
        userData.T1 = parameter.B1.modPow(user.secList.get(5), parameter.Sigma).multiply(parameter.B2.modPow(userData.rand_, parameter.Sigma)).mod(parameter.Sigma);   //T1 = b1^(i)*b2^(r') mod sigma
        userData.T2 = userData.T1.modPow(user.secList.get(6), parameter.Sigma);                                                                                       //T2 = T1^e mod sigma
        userData.dA_ = numberTools.modPowList(parameter.Qrn.QRPList.toArray(new BigInteger[parameter.Qrn.QRPList.size()]), userData.rList.subList(1, 8).toArray(new BigInteger[7]), parameter.N);    //dA_ = ax^(r2)*as^(r3)*at^(r4)*ai^(r5)*ae^(r6)*ad^(r7)*h^(r8) mod n
        userData.dA_ = userData.dA_.modInverse(parameter.N);
        userData.dA = userData.A_.modPow(userData.rList.get(0), parameter.N).multiply(userData.dA_).mod(parameter.N);                                                    //dA = (A')^(r1)/dA_ mod n
        userData.dT = parameter.B1.modPow(userData.rList.get(3), parameter.Sigma).multiply(parameter.B2.modPow(userData.rList.get(8), parameter.Sigma)).mod(parameter.Sigma); // dT = b1^(r4)*b2^(r9) mod sigma
        userData.dT1 = parameter.B1.modPow(userData.rList.get(4), parameter.Sigma).multiply(parameter.B2.modPow(userData.rList.get(9), parameter.Sigma)).mod(parameter.Sigma);// dT1 = b1^(r5)*b2^(r10) mod sigma
        userData.dT2 = userData.T1.modPow(userData.rList.get(5), parameter.Sigma);                                                                                    // dT2 = T1^(r6) mod sigma
        userData.dT2_ = parameter.B1.modPow(userData.rList.get(10), parameter.Sigma).multiply(parameter.B2.modPow(userData.rList.get(11), parameter.Sigma)).mod(parameter.Sigma); //dT2' = b1^(r11)*b2^(r12) mod sigma
        userData.dT3_ = userData.rList.get(12).subtract(userData.rList.get(5).add(userData.rList.get(6))).mod(parameter.K_at);                                       //dT3_ = r13-r6-r7
        userData.dT3 = parameter.B.modPow(userData.dT3_, parameter.Sigma);                                                                                            //dT3 = b^(dT3_) mod sigma
        if (userData.flag == 0) {
            userData.dic_ = userData.ic.multiply(userData.rList.get(5)).subtract(userData.rList.get(10)).mod(parameter.K_at);
            //dic_ = ic*r6 - r11-K_at * r14
        } else if (userData.flag == 1){
            userData.dic_ = userData.ic.subtract(Parameter.bigOne).multiply(userData.rList.get(5)).subtract(userData.rList.get(10)).mod(parameter.K_at);
        } else {
            userData.dic_ = userData.ic.subtract(Parameter.bigTwo).multiply(userData.rList.get(5)).subtract(userData.rList.get(10)).mod(parameter.K_at);
        }
        userData.dic = parameter.Qrn.A.modPow(userData.dic_, parameter.N);                                                                                            //dic = a^(dic_) mod n
        userData.dSN1 = userData.SN.modPow(userData.rList.get(2), parameter.Sigma).multiply(parameter.B2.modPow(userData.rList.get(14), parameter.Sigma).modInverse(parameter.Sigma)).mod(parameter.Sigma); //dSN1 = SN^(r3)*((b2)^(r15))^(-1) mod sigma
        userData.dSN2 = userData.SN.modPow(userData.rList.get(3), parameter.Sigma).multiply(parameter.B1.modPow(userData.rList.get(15), parameter.Sigma).modInverse(parameter.Sigma)).mod(parameter.Sigma); //dSN2 = SN^(r4)*((b1)^(r16))^(-1) mod sigma
        userData.dD = parameter.Qrn.Ax.modPow(userData.rList.get(1), parameter.N);                                                                                                   //dD = ax^(r2)*as^(r3)*at^(r4)*ae^(r13)*ad^(r7)*h^(r8) mod n
        userData.dD = userData.dD.multiply(parameter.Qrn.As.modPow(userData.rList.get(2), parameter.N)).mod(parameter.N);
        userData.dD = userData.dD.multiply(parameter.Qrn.At.modPow(userData.rList.get(3), parameter.N)).mod(parameter.N);
        userData.dD = userData.dD.multiply(parameter.Qrn.Ae.modPow(userData.rList.get(12), parameter.N)).mod(parameter.N);
        userData.dD = userData.dD.multiply(parameter.Qrn.Ad.modPow(userData.rList.get(6), parameter.N)).mod(parameter.N);
        userData.dD = userData.dD.multiply(parameter.Qrn.h.modPow(userData.rList.get(7), parameter.N)).mod(parameter.N);
        ScanCodeFirstRequest scanCodeFirstRequest = new ScanCodeFirstRequest(userData);
        userData.rand2 = userData.rList;

        //save userData
        List<Object> list = new ArrayList<>();
        list.add(userData);
        list.add(scanCodeFirstRequest);
        return list;
    }



/*    public static void main(String[] args) {
        UserCipherServiceImpl userCipherService = new UserCipherServiceImpl();
        GMServiceImpl gmService = new GMServiceImpl();
        UserPrivateData user = new UserPrivateData();
        user.a = new BigInteger("245192188116836622283117471736126991298160888165365904028281043119282428470246");
        user.y = new BigInteger("1645504557321206042154969182557350504982736777164207737244888117");
        user.secList.add(new BigInteger("937462413898486014101237229714"));
        user.secList.add(new BigInteger("1092675885328096609485"));
        user.secList.add(new BigInteger("1051269604147203894089"));
        user.secList.add(new BigInteger("2942103974079436064973926219584156934665158153454069742321080"));
        user.secList.add(new BigInteger("1799793775804218449742"));
        user.secList.add(new BigInteger("749"));
        user.secList.add(new BigInteger("735"));
        user.secList.add(new BigInteger("587"));
        user.secList.add(new BigInteger("653459521915116468862"));

        *   secList = [, , , , , , , , ]
            A = 245192188116836622283117471736126991298160888165365904028281043119282428470246
            y = 1645504557321206042154969182557350504982736777164207737244888117
            *
            *r = [2454048499088907426850044654677680868840118763904718281454988, 1729154999622464318104779462692092309174662337078239796248799, 194046851434203066183852267735062205794413293657957485447006575063819119440798166309621241505820170849123044589947853815, 2648108433319113667513394113894484281330918111266439707926740, 2363732846917050118978855592389530, 1993701000890375276106935966151994, 1875257329371500252249677709280103, 178787059232847684595937038117355439085935837868477200676109954216661703175284133717622466319746638644871232160298585277164911234784426266709677792683087834, 1925990756054739847639759381591013923278652169461221006232408, 2184895329618754109795547759470547243768678463285601758041259, 47817344072691413283676940914868089932, 56655430415432750701544498208470742478456414408132536535105729083, 1530004010310155064457331794777250, 1893223051216794616051781440019157, 2007801680400108195757584475555843364022796629802812723610970649337539596215243987742470028794244404784213386264489182059543104887699802546391501514898760490971026743968920380275739384278658310713940742815682080, 2586338660834897691960699471524765375965177001970781313063057323415630239936869180661291750738603799231803577020677978135307742488803756295512482987963794509270526230480672196462646732925737162065815758839022178]
w2 = 847396559708088136536
rand = 1173124413681130002761
rand_ = 957403239301540735485
        *
        List<Object> list = userCipherService.scanCodeRequestFirstTest(user);
        UserScanCodeData userData = (UserScanCodeData) list.get(0);
        ScanCodeFirstRequest requestData =  ( ScanCodeFirstRequest )list.get(1);
        requestData.Out();
        String challenge = gmService.scanCodeFirstTest(requestData);
        ScanCodeSecondRequest scanCodeSecondRequest= userCipherService.scanCodeRequestSecond(user,userData,requestData,challenge);
        scanCodeSecondRequest.Out();
    } */

}
